﻿using Bilibili.Common.Database.Table;
using Bilibili.Common.Log;
using Bilibili.Model.Common;
using Bilibili.Model.User;
using PCLUntils.Json;
using PCLUntils.Objects;
using System;
using System.Collections.Generic;

namespace Bilibili.Common.Database
{
    public sealed class SettingHelper
    {
        private const string DEFAULT_COOKIES = "SESSDATA=0;bili_jct=0;sid=0;DedeUserID=0;DedeUserID__ckMd5=0;";
        public static string AccessKey
        {
            get=> GetData("AccessKey", out string value) ? value : string.Empty;
            set => SaveData("AccessKey", value);
        }
        public static long UserID
        {
            get
            {
                try
                {
                    if (GetData("UserID", out string value))
                        return Convert.ToInt64(value);
                    else return 0;
                }
                catch { return 0; }
            }
            set => SaveData("UserID", value.ToString());
        }
        public static string Version
        {
            get
            {
                try
                {
                    return GetData("Version", out string value) ? value : string.Empty;
                }
                catch { return string.Empty; }
            }
            set => SaveData("Version", value);
        }
        public static Area UseArea
        {
            get
            {
                if (GetData("Version", out string value))
                {
                    return value switch
                    {
                        "HK" => Area.HK,
                        "TW" => Area.TW,
                        _ => Area.ND,
                    };
                }
                else { return Area.ND; }
            }
            set => SaveData("UseArea", value.ToString());
        }
        public static DateTime LoginExpires
        {
            get
            {
                try
                {
                    return GetData("LoginExpires", out string value) ? Convert.ToInt64(value).ToDateTime() : DateTime.MinValue;
                }
                catch { return DateTime.MinValue; }
            }
            set => SaveData("LoginExpires", value.ToTimeStamp().ToString());
        }
        public static string RefreshToken
        {
            get
            {
                try
                {
                    return GetData("RefreshToken", out string value) ? value : string.Empty;
                }
                catch { return string.Empty; }
            }
            set => SaveData("RefreshToken", value.ToString());
        }
        public static bool FingerAuth
        {
            get
            {
                GetData("FingerAuth", out string value);
                return value == "1";
            }
            set => SaveData("FingerAuth", value ? "1" : "0");
        }
        public static string BiliPlusCookie
        {
            get
            {
                try
                {
                    return GetData("BiliPlusCookie", out string value) ? value : string.Empty;
                }
                catch { return string.Empty; }
            }
            set => SaveData("BiliPlusCookie", value.ToString());
        }
        public static string UserInfoCookie
        {
            get
            {
                try
                {
                    GetData("UserInfoCookie", out string value);
                    if (value.IsEmpty())
                        value = DEFAULT_COOKIES;
                    return value;
                }
                catch { return DEFAULT_COOKIES; }
            }
            set => SaveData("UserInfoCookie", value);
        }
        public static string Password
        {
            get
            {
                try
                {
                    return GetData("Password", out string value) ? value : string.Empty;
                }
                catch { return string.Empty; }
            }
            set => SaveData("Password", value.ToString());
        }
        public static UserInfo UserInfo
        {
            get
            {
                try
                {
                    if (GetData("UserInfo", out string value))
                        return value.ParseObject<UserInfo>();
                    else return default;
                }
                catch { return default; }
            }
            set => SaveData("UserInfo", value.ParseJson());
        }
        public static string UserHead
        {
            get
            {
                try
                {
                    return GetData("UserHead", out string value) ? value : string.Empty;
                }
                catch { return string.Empty; }
            }
            set => SaveData("UserHead", value);
        }
        public static string DownloadPath
        {
            get
            {
                GetData("DownloadPath", out string value);
                return value;
            }
            set => SaveData("DownloadPath", value);
        }
        public static bool UseDASH
        {
            get
            {
                try
                {
                    GetData("UseDASH", out string value);
                    return value == "1";
                }
                catch { return true; }
            }
            set => SaveData("UseDASH", value ? "1" : "0");
        }
        public static bool UseHEVC
        {
            get
            {
                try
                {
                    GetData("UseHEVC", out string value);
                    return value == "1";
                }
                catch { return false; }
            }
            set => SaveData("UseHEVC", value ? "1" : "0");
        }
        public static double SeekValue
        {
            get
            {
                try
                {
                    GetData("SeekValue", out string value);
                    return double.TryParse(value, out double result) ? result : 0.02;
                }
                catch { return 0.02; }
            }
            set => SaveData("SeekValue", value.ToString());
        }
        public static int DanmakuSize
        {
            get
            {
                try
                {
                    GetData("DanmuSize", out string value);
                    return int.TryParse(value, out int result) ? result : 12;
                }
                catch { return 12; }
            }
            set => SaveData("DanmuSize", value.ToString());
        }
        public static int DanmakuSpeed
        {
            get
            {
                try
                {
                    GetData("DanmakuSpeed", out string value);
                    return int.TryParse(value, out int result) ? result : 12;
                }
                catch { return 12; }
            }
            set => SaveData("DanmakuSpeed", value.ToString());
        }
        public static bool EnableLogging
        {
            get
            {
                try
                {
                    GetData("EnableLogging", out string value);
                    return value == "1";
                }
                catch { return true; }
            }
            set => SaveData("EnableLogging", value ? "1" : "0");
        }
        public static bool FullScreenPlayer
        {
            get
            {
                try
                {
                    GetData("FullScreenPlayer", out string value);
                    return value == "1";
                }
                catch { return true; }
            }
            set => SaveData("FullScreenPlayer", value ? "1" : "0");
        }
        public static bool DanmakuStatus
        {
            get
            {
                try
                {
                    GetData("DanmakuStatus", out string value);
                    return value == "1";
                }
                catch { return true; }
            }
            set => SaveData("DanmakuStatus", value ? "1" : "0");
        }
        public static bool IsIJKPlayer
        {
            get
            {
                try
                {
                    GetData("IsIJKPlayer", out string value);
                    return value == "1";
                }
                catch { return false; }
            }
            set => SaveData("IsIJKPlayer", value ? "1" : "0");
        }
        public static bool DarkTheme
        {
            get
            {
                try
                {
                    GetData("DarkTheme", out string value);
                    return value == "1";
                }
                catch { return false; }
            }
            set => SaveData("DarkTheme", value ? "1" : "0");
        }
        public static bool UseRest
        {
            get
            {
                try
                {
                    GetData("UseRest", out string value);
                    return value == "1";
                }
                catch { return false; }
            }
            set => SaveData("UseRest", value ? "1" : "0");
        }
        public static string Buvid
        {
            get
            {
                try
                {
                    GetData("Buvid", out string value);
                    return value;
                }
                catch { return string.Empty; }
            }
            set => SaveData("Buvid", value);
        }
        private static bool GetData(string name, out string value)
        {
            try
            {
                using (DB db = new DB())
                {
                    var entity = db.Connection.Table<Setting>().FirstOrDefault(x => x.Name == name);
                    value = entity?.Value;
                }
                if (string.IsNullOrEmpty(value))
                    value = string.Empty;
                return true;
            }
            catch
            {
                value = string.Empty;
                return false;
            }
        }
        private static void SaveData(string name, string value)
        {
            try
            {
                using DB db = new DB();
                var entity = db.Connection.Table<Setting>().FirstOrDefault(x => x.Name == name);
                if (entity.IsNotEmpty())
                {
                    entity.Value = value;
                    db.Connection.Update(entity);
                }
                else
                {
                    entity = new Setting
                    {
                        Value = value,
                        Name = name
                    };
                    db.Connection.Insert(entity);
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("SaveData", ex);
            }
        }
        public static void AddDanmakuFilter(DB db, int type, string oid, string keyword)
        {
            try
            {
                var entity = db.Connection.Table<DanmakuFilterTab>().FirstOrDefault(x => x.Keyword == keyword);
                if (entity.IsEmpty())
                {
                    entity = new DanmakuFilterTab
                    {
                        OId = oid,
                        Type = type,
                        Keyword = keyword
                    };
                    db.Connection.Insert(entity);
                }
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("AddDanmakuFilter", ex);
            }
        }
        public static void RemoveDanmakuFilter(string oid, int type)
        {
            try
            {
                using DB db = new DB();
                db.Connection.Table<DanmakuFilterTab>().Delete(x => x.OId == oid && x.Type == type);
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("RemoveDanmakuFilter", ex);
            }
        }
        public static List<DanmakuFilterTab> GetDanmakuFilter(int? type = null)
        {
            try
            {
                using DB db = new DB();
                if (type.HasValue)
                    return db.Connection.Table<DanmakuFilterTab>().Where(x => x.Type == type).ToList();
                else
                    return db.Connection.Table<DanmakuFilterTab>().ToList();
            }
            catch (Exception ex)
            {
                LogManager.Instance.LogError("AddDanmakuFilter", ex);
                return null;
            }
        }
    }
}